/**
 * 资源管理器
 *
 * 管理图片、视频等二进制资源的存储和引用
 */

import type { StorageResult } from '../types'
import { StorageErrorCode } from '../storageErrors'
import { AppDatabase } from './database'
import type { StoredAsset } from './types'

/**
 * AssetManager类
 * 负责资源的CRUD操作和引用管理
 */
export class AssetManager {
  constructor(private db: AppDatabase) {}

  /**
   * 保存图片资源
   * @param file File对象或Blob
   * @param name 文件名
   * @returns 资源ID
   */
  async saveImage(file: File | Blob, name: string): Promise<StorageResult<string>> {
    try {
      console.log('[资源管理] 保存图片', name, `${(file.size / 1024).toFixed(2)}KB`)

      const assetId = `asset-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`

      const asset: StoredAsset = {
        id: assetId,
        type: 'image',
        name,
        data: file,
        size: file.size,
        mimeType: file.type,
        createdAt: Date.now(),
        references: []
      }

      await this.db.assets.add(asset)

      console.log('[资源管理] 图片已保存', assetId)
      return { ok: true, data: assetId }
    } catch (error) {
      console.error('[资源管理] 保存图片失败', error)
      return {
        ok: false,
        error: {
          code: StorageErrorCode.UNKNOWN,
          message: '保存图片失败',
          cause: error
        }
      }
    }
  }

  /**
   * 保存视频资源
   * @param file File对象或Blob
   * @param name 文件名
   * @returns 资源ID
   */
  async saveVideo(file: File | Blob, name: string): Promise<StorageResult<string>> {
    try {
      console.log('[资源管理] 保存视频', name, `${(file.size / 1024 / 1024).toFixed(2)}MB`)

      const assetId = `asset-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`

      const asset: StoredAsset = {
        id: assetId,
        type: 'video',
        name,
        data: file,
        size: file.size,
        mimeType: file.type,
        createdAt: Date.now(),
        references: []
      }

      await this.db.assets.add(asset)

      console.log('[资源管理] 视频已保存', assetId)
      return { ok: true, data: assetId }
    } catch (error) {
      console.error('[资源管理] 保存视频失败', error)
      return {
        ok: false,
        error: {
          code: StorageErrorCode.UNKNOWN,
          message: '保存视频失败',
          cause: error
        }
      }
    }
  }

  /**
   * 读取资源
   * @param assetId 资源ID
   * @returns Blob对象和URL
   */
  async getAsset(assetId: string): Promise<StorageResult<{ blob: Blob; url: string; asset: StoredAsset }>> {
    try {
      console.log('[资源管理] 读取资源', assetId)

      const asset = await this.db.assets.get(assetId)
      if (!asset) {
        console.log('[资源管理] 资源不存在')
        return {
          ok: false,
          error: {
            code: StorageErrorCode.UNKNOWN,
            message: '资源不存在'
          }
        }
      }

      // 创建Blob URL供显示
      const url = URL.createObjectURL(asset.data)

      console.log('[资源管理] 资源已读取')
      return {
        ok: true,
        data: {
          blob: asset.data,
          url,
          asset
        }
      }
    } catch (error) {
      console.error('[资源管理] 读取资源失败', error)
      return {
        ok: false,
        error: {
          code: StorageErrorCode.UNKNOWN,
          message: '读取资源失败',
          cause: error
        }
      }
    }
  }

  /**
   * 获取图片资源
   * 便捷方法,同getAsset
   */
  async getImage(assetId: string): Promise<StorageResult<{ blob: Blob; url: string }>> {
    const result = await this.getAsset(assetId)
    if (!result.ok) {
      return result
    }

    const { blob, url } = result.data
    return { ok: true, data: { blob, url } }
  }

  /**
   * 删除资源(检查引用)
   * @param assetId 资源ID
   * @param force 是否强制删除(忽略引用检查)
   */
  async deleteAsset(assetId: string, force = false): Promise<StorageResult<void>> {
    try {
      console.log('[资源管理] 删除资源', assetId, force ? '(强制)' : '')

      const asset = await this.db.assets.get(assetId)
      if (!asset) {
        console.log('[资源管理] 资源不存在,跳过删除')
        return { ok: true, data: undefined }
      }

      // 检查引用(除非强制删除)
      if (!force && asset.references && asset.references.length > 0) {
        console.warn('[资源管理] 资源仍被引用,无法删除', asset.references)
        return {
          ok: false,
          error: {
            code: StorageErrorCode.UNKNOWN,
            message: `资源被${asset.references.length}个文档引用,无法删除`,
            cause: { references: asset.references }
          }
        }
      }

      await this.db.assets.delete(assetId)

      console.log('[资源管理] 资源已删除')
      return { ok: true, data: undefined }
    } catch (error) {
      console.error('[资源管理] 删除资源失败', error)
      return {
        ok: false,
        error: {
          code: StorageErrorCode.UNKNOWN,
          message: '删除资源失败',
          cause: error
        }
      }
    }
  }

  /**
   * 更新资源引用
   * 当文档中添加/移除资源引用时调用
   * @param assetId 资源ID
   * @param documentId 文档ID
   * @param action 'add'添加引用, 'remove'移除引用
   */
  async updateReferences(
    assetId: string,
    documentId: string,
    action: 'add' | 'remove'
  ): Promise<StorageResult<void>> {
    try {
      console.log('[资源管理] 更新引用', assetId, documentId, action)

      const asset = await this.db.assets.get(assetId)
      if (!asset) {
        return {
          ok: false,
          error: {
            code: StorageErrorCode.UNKNOWN,
            message: '资源不存在'
          }
        }
      }

      const references = asset.references || []

      if (action === 'add') {
        // 添加引用(避免重复)
        if (!references.includes(documentId)) {
          references.push(documentId)
          console.log('[资源管理] 引用已添加')
        } else {
          console.log('[资源管理] 引用已存在,跳过')
        }
      } else {
        // 移除引用
        const index = references.indexOf(documentId)
        if (index > -1) {
          references.splice(index, 1)
          console.log('[资源管理] 引用已移除')
        } else {
          console.log('[资源管理] 引用不存在,跳过')
        }
      }

      // 更新资源
      await this.db.assets.update(assetId, { references })

      return { ok: true, data: undefined }
    } catch (error) {
      console.error('[资源管理] 更新引用失败', error)
      return {
        ok: false,
        error: {
          code: StorageErrorCode.UNKNOWN,
          message: '更新资源引用失败',
          cause: error
        }
      }
    }
  }

  /**
   * 获取资源的引用列表
   * @param assetId 资源ID
   * @returns 引用此资源的文档ID列表
   */
  async getReferences(assetId: string): Promise<StorageResult<string[]>> {
    try {
      console.log('[资源管理] 获取引用列表', assetId)

      const asset = await this.db.assets.get(assetId)
      if (!asset) {
        return {
          ok: false,
          error: {
            code: StorageErrorCode.UNKNOWN,
            message: '资源不存在'
          }
        }
      }

      const references = asset.references || []
      console.log(`[资源管理] 找到${references.length}个引用`)
      return { ok: true, data: references }
    } catch (error) {
      console.error('[资源管理] 获取引用列表失败', error)
      return {
        ok: false,
        error: {
          code: StorageErrorCode.UNKNOWN,
          message: '获取引用列表失败',
          cause: error
        }
      }
    }
  }

  /**
   * 清理未引用的资源
   * 定期清理没有任何文档引用的孤立资源
   * @returns 删除的资源数量
   */
  async cleanupUnusedAssets(): Promise<StorageResult<{ deletedCount: number; freedBytes: number }>> {
    try {
      console.log('[资源管理] 开始清理未引用资源')

      const allAssets = await this.db.assets.toArray()
      let deletedCount = 0
      let freedBytes = 0

      for (const asset of allAssets) {
        if (!asset.references || asset.references.length === 0) {
          await this.db.assets.delete(asset.id)
          deletedCount++
          freedBytes += asset.size
          console.log(`[资源管理] 删除未引用资源: ${asset.name}`)
        }
      }

      console.log(
        `[资源管理] 清理完成: 删除${deletedCount}个资源, 释放${(freedBytes / 1024 / 1024).toFixed(2)}MB`
      )
      return {
        ok: true,
        data: {
          deletedCount,
          freedBytes
        }
      }
    } catch (error) {
      console.error('[资源管理] 清理失败', error)
      return {
        ok: false,
        error: {
          code: StorageErrorCode.UNKNOWN,
          message: '清理未引用资源失败',
          cause: error
        }
      }
    }
  }

  /**
   * 获取所有资源列表
   * @param type 可选的资源类型筛选
   * @returns 资源列表
   */
  async listAssets(type?: 'image' | 'video' | 'audio'): Promise<StorageResult<StoredAsset[]>> {
    try {
      console.log('[资源管理] 获取资源列表', type || '全部')

      let assets: StoredAsset[]
      if (type) {
        assets = await this.db.assets.where('type').equals(type).toArray()
      } else {
        assets = await this.db.assets.toArray()
      }

      // 按创建时间倒序排序
      assets.sort((a, b) => b.createdAt - a.createdAt)

      console.log(`[资源管理] 找到${assets.length}个资源`)
      return { ok: true, data: assets }
    } catch (error) {
      console.error('[资源管理] 获取资源列表失败', error)
      return {
        ok: false,
        error: {
          code: StorageErrorCode.UNKNOWN,
          message: '获取资源列表失败',
          cause: error
        }
      }
    }
  }

  /**
   * 获取资源使用统计
   * @returns 统计信息
   */
  async getUsageStats(): Promise<
    StorageResult<{
      totalCount: number
      imageCount: number
      videoCount: number
      audioCount: number
      totalSize: number
      unusedCount: number
    }>
  > {
    try {
      console.log('[资源管理] 获取使用统计')

      const allAssets = await this.db.assets.toArray()

      let imageCount = 0
      let videoCount = 0
      let audioCount = 0
      let totalSize = 0
      let unusedCount = 0

      for (const asset of allAssets) {
        // 按类型统计
        if (asset.type === 'image') imageCount++
        else if (asset.type === 'video') videoCount++
        else if (asset.type === 'audio') audioCount++

        // 大小统计
        totalSize += asset.size

        // 未引用统计
        if (!asset.references || asset.references.length === 0) {
          unusedCount++
        }
      }

      const stats = {
        totalCount: allAssets.length,
        imageCount,
        videoCount,
        audioCount,
        totalSize,
        unusedCount
      }

      console.log('[资源管理] 统计完成:', stats)
      return { ok: true, data: stats }
    } catch (error) {
      console.error('[资源管理] 获取统计失败', error)
      return {
        ok: false,
        error: {
          code: StorageErrorCode.UNKNOWN,
          message: '获取资源使用统计失败',
          cause: error
        }
      }
    }
  }
}
